#pragma once
#include <windows.h>
#include <utility>
#include <stdexcept>
namespace CppWinApi::Windows
{
    class ProcessInformation
    {
        HANDLE mProcess = nullptr;
        HANDLE mThread = nullptr;
        DWORD mProcessId = 0;
        DWORD mThreadId = 0;

    public:
        // 默认构造函数
        ProcessInformation() = default;

        // 从 PROCESS_INFORMATION 构造（接管所有权）
        explicit ProcessInformation(PROCESS_INFORMATION &pi) noexcept : mProcess(pi.hProcess),
                                                                        mThread(pi.hThread),
                                                                        mProcessId(pi.dwProcessId),
                                                                        mThreadId(pi.dwThreadId) {}

        // 禁止拷贝构造（避免重复关闭句柄）
        ProcessInformation(const ProcessInformation &) = delete;
        ProcessInformation &operator=(const ProcessInformation &) = delete;

        // 移动构造
        ProcessInformation(ProcessInformation &&other) noexcept : mProcess(std::exchange(other.mProcess, nullptr)),
                                                                  mThread(std::exchange(other.mThread, nullptr)),
                                                                  mProcessId(std::exchange(other.mProcessId, 0)),
                                                                  mThreadId(std::exchange(other.mThreadId, 0)) {}

        // 移动赋值
        ProcessInformation &operator=(ProcessInformation &&other) noexcept
        {
            if (this != &other)
            {
                Close(); // 先释放当前资源
                mProcess = std::exchange(other.mProcess, nullptr);
                mThread = std::exchange(other.mThread, nullptr);
                mProcessId = std::exchange(other.mProcessId, 0);
                mThreadId = std::exchange(other.mThreadId, 0);
            }
            return *this;
        }

        // 析构函数
        ~ProcessInformation()
        {
            Close();
        }

        // 显式关闭所有句柄
        void Close() noexcept
        {
            if (mProcess)
            {
                CloseHandle(mProcess);
                mProcess = nullptr;
            }
            if (mThread)
            {
                CloseHandle(mThread);
                mThread = nullptr;
            }
            mProcessId = 0;
            mThreadId = 0;
        }

        // 转换为 PROCESS_INFORMATION（不转移所有权）
        PROCESS_INFORMATION Get() const noexcept
        {
            PROCESS_INFORMATION pi = {};
            pi.hProcess = mProcess;
            pi.hThread = mThread;
            pi.dwProcessId = mProcessId;
            pi.dwThreadId = mThreadId;
            return pi;
        }

        // 转换为 PROCESS_INFORMATION（转移所有权）
        PROCESS_INFORMATION Release() noexcept
        {
            PROCESS_INFORMATION pi = {};
            pi.hProcess = std::exchange(mProcess, nullptr);
            pi.hThread = std::exchange(mThread, nullptr);
            pi.dwProcessId = std::exchange(mProcessId, 0);
            pi.dwThreadId = std::exchange(mThreadId, 0);
            return pi;
        }

        // 获取各个成员
        HANDLE GetProcess() const noexcept { return mProcess; }
        HANDLE GetThread() const noexcept { return mThread; }
        DWORD GetProcessId() const noexcept { return mProcessId; }
        DWORD GetThreadId() const noexcept { return mThreadId; }

        // 检查是否有效
        explicit operator bool() const noexcept
        {
            return mProcess != nullptr || mThread != nullptr;
        }

        // 等待进程退出
        DWORD WaitForExit(DWORD timeout = INFINITE) const
        {
            if (!mProcess)
            {
                throw std::runtime_error("Invalid process handle");
            }
            if (WaitForSingleObject(mProcess, timeout) == WAIT_FAILED)
            {
                throw std::system_error(
                    GetLastError(),
                    std::system_category(),
                    "WaitForSingleObject failed");
            }

            DWORD exitCode = 0;
            if (!GetExitCodeProcess(mProcess, &exitCode))
            {
                throw std::system_error(
                    GetLastError(),
                    std::system_category(),
                    "GetExitCodeProcess failed");
            }
            return exitCode;
        }
    };
}